#include <ka_command.h>
#include <string.h>
#include <stdio.h>

const static char admin_path[] = "/usr/bin/kacfg";

static const TEE_UUID tee_client_uuid_ns = {0xa09cac58, 0x8620, 0x8346, {0xa1, 0xb8, 0xec, 0x4b, 0xc0, 0x8e, 0x01, 0xb6}};

#define KEY_ID_MAX_SIZE 64

#define UUID_EQUAL(uuida, uuidb) (memcmp(&uuida, &uuidb, sizeof(TEE_UUID)) == 0)

const char *uuid2str(const unsigned char *uuid)
{
    static char uuid_str[37];
    snprintf(uuid_str, sizeof(uuid_str),
             "%02x%02x%02x%02x-"
             "%02x%02x-"
             "%02x%02x-"
             "%02x%02x-"
             "%02x%02x%02x%02x%02x%02x",
             uuid[0], uuid[1], uuid[2], uuid[3],
             uuid[4], uuid[5],
             uuid[6], uuid[7],
             uuid[8], uuid[9],
             uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
    return uuid_str;
}

const char *hexStr(const uint8_t *buf, int len)
{
    static char tmp[128];

    for (int i = 0; i < len; i++)
    {
        snprintf(tmp + i * 2, 3, "%02x", buf[i]);
    }

    return tmp;
}

// FIX: UUID byte endian order incorrect
TEE_Result path2uuid(const char *full_path, TEE_UUID *tee_uuid)
{
    TEE_OperationHandle operation = {0};
    TEE_Result rc = TEE_SUCCESS;
    uint8_t hash[SHA1_DIGEST_SIZE];
    size_t hash_len = SHA1_DIGEST_SIZE;
    uint8_t uuid[16];
    DMSG("path2uuid for %s\n", full_path);
    rc = TEE_AllocateOperation(&operation, TEE_ALG_SHA1, TEE_MODE_DIGEST, SHA1_DIGEST_SIZE * 8);
    if (rc)
        return rc;

    rc = TEE_DigestDoFinal(operation, full_path, strlen(full_path), hash, &hash_len);
    if (rc)
        return rc;

    TEE_DigestUpdate(operation, &tee_client_uuid_ns, sizeof(tee_client_uuid_ns));
    const char *sha1_str = hexStr(hash, SHA1_DIGEST_SIZE);
    rc = TEE_DigestDoFinal(operation, sha1_str, SHA1_DIGEST_SIZE * 2 + 1, hash, &hash_len);
    if (rc)
        return rc;
    // DMSG("full path hash [%s]\n", sha1_str);
    memcpy(uuid, hash, sizeof(uuid));
    /* Tag for version 5 */
    uuid[6] = (hash[6] & 0x0F) | 0x50;
    uuid[8] = (hash[8] & 0x3F) | 0x80;
    DMSG("uuid hash [%s]\n", hexStr(hash, SHA1_DIGEST_SIZE));

    uint8_t *p = (uint8_t *)tee_uuid;
    p[0] = uuid[3];
    p[1] = uuid[2];
    p[2] = uuid[1];
    p[3] = uuid[0];
    p[4] = uuid[5];
    p[5] = uuid[4];
    p[6] = uuid[7];
    p[7] = uuid[6];
    for (size_t i = 8; i < 16; i++)
    {
        p[i] = uuid[i];
    }

    DMSG("[%s] uuid is [%s]\n", full_path, uuid2str(uuid));

    DMSG("[%s] tee uuid is [%s]\n", full_path, uuid2str(tee_uuid));

    TEE_FreeOperation(operation);
    return TEE_SUCCESS;
}

typedef struct
{
    TEE_UUID uuid;
    uint32_t flag;
} ACL_Meta;
#define ACL_META_FLAG_VALID_MASK 0x80000000

TEE_Result KA_ACL_Create(TEE_ObjectHandle *object, TEE_UUID uuid)
{
    char *obj_id = uuid2str(&uuid);
    size_t obj_id_size = strlen(obj_id);
    TEE_Result rc = TEE_SUCCESS;
    char key_id[KEY_ID_MAX_SIZE];
    size_t key_id_size = snprintf(key_id, KEY_ID_MAX_SIZE, "%s.key", obj_id);
    TEE_ObjectHandle key;
    TEE_ObjectHandle persistent_key;
    const uint32_t key_type = TEE_TYPE_RSA_KEYPAIR;
    const size_t key_size = 1024;

    rc = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE, obj_id, obj_id_size, TEE_DATA_FLAG_ACCESS_READ | TEE_DATA_FLAG_ACCESS_WRITE, TEE_HANDLE_NULL, NULL, 0, object);
    if (rc)
    {
        DMSG("OBJ[%s] create failed, error 0x%08x\n", obj_id, rc);
        return rc;
    }
    /* Generate key pair */
    rc = TEE_AllocateTransientObject(key_type, key_size, &key);
    if (rc)
    {
        TEE_CloseAndDeletePersistentObject(*object);
        return rc;
    }
    rc = TEE_GenerateKey(key, key_size, NULL, 0);
    if (rc)
    {
        TEE_FreeTransientObject(key);
        TEE_CloseAndDeletePersistentObject(*object);
        return rc;
    }
    /* save key pair */
    rc = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE, key_id, key_id_size, TEE_DATA_FLAG_ACCESS_READ | TEE_DATA_FLAG_ACCESS_WRITE, key, NULL, 0, &persistent_key);
    if (rc)
    {
        TEE_FreeTransientObject(key);
        TEE_CloseAndDeletePersistentObject(*object);
        return rc;
    }
    DMSG("Generate Key [%s]", key_id);
    TEE_FreeTransientObject(key);
    TEE_CloseObject(persistent_key);
    return rc;
}

TEE_Result KA_ACL_Open(TEE_ObjectHandle *object, TEE_UUID uuid)
{
    char *obj_id = uuid2str(&uuid);
    size_t obj_id_size = strlen(obj_id);
    TEE_Result rc = TEE_SUCCESS;
    rc = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, obj_id, obj_id_size, TEE_DATA_FLAG_ACCESS_READ | TEE_DATA_FLAG_ACCESS_WRITE, object);
    return rc;
}

void KA_ACL_Close(TEE_ObjectHandle object)
{
    TEE_CloseObject(object);
}

TEE_Result KA_ACL_Find(TEE_ObjectHandle object, TEE_UUID uuid)
{
    TEE_Result rc = TEE_SUCCESS;
    ACL_Meta data;
    uint32_t count = 0;
    rc = TEE_SeekObjectData(object, 0, TEE_DATA_SEEK_SET);
    if (rc)
        return rc;
    do
    {
        rc = TEE_ReadObjectData(object, &data, sizeof(data), &count);
        if (rc)
            return rc;
        if (count == 0)
            break;
        if (count != sizeof(data))
        {
            EMSG("acl file data size not correct!");
            return TEE_ERROR_BAD_FORMAT;
        }
        if (UUID_EQUAL(data.uuid, uuid))
        {
            if (data.flag & ACL_META_FLAG_VALID_MASK)
            {
                return TEE_SUCCESS;
            }
            else
            {
                return TEE_ERROR_ACCESS_DENIED;
            }
        }
    } while (count);
    return TEE_ERROR_ITEM_NOT_FOUND;
}

TEE_Result KA_ACL_Delete(TEE_ObjectHandle object, TEE_UUID uuid)
{
    TEE_Result rc = TEE_SUCCESS;
    ACL_Meta data;
    uint32_t count = 0;
    rc = TEE_SeekObjectData(object, 0, TEE_DATA_SEEK_SET);
    if (rc)
        return rc;
    do
    {
        rc = TEE_ReadObjectData(object, &data, sizeof(data), &count);
        if (rc)
            return rc;
        if (count == 0)
            break;
        if (count != sizeof(data))
        {
            EMSG("acl file data size not correct!");
            return TEE_ERROR_BAD_FORMAT;
        }
        if (data.flag & ACL_META_FLAG_VALID_MASK && UUID_EQUAL(data.uuid, uuid))
        {
            rc = TEE_SeekObjectData(object, -sizeof(data), TEE_DATA_SEEK_CUR);
            if (rc)
                return rc;
            data.flag &= ~ACL_META_FLAG_VALID_MASK;
            rc = TEE_WriteObjectData(object, &data, sizeof(data));
            return rc;
        }
    } while (count);
    return TEE_ERROR_ITEM_NOT_FOUND;
}

TEE_Result KA_ACL_Add(TEE_ObjectHandle object, TEE_UUID uuid)
{
    TEE_Result rc = TEE_SUCCESS;
    TEE_ObjectInfo objectInfo;
    ACL_Meta data;
    size_t count = 0;
    rc = KA_ACL_Find(object, uuid);
    if (rc == TEE_SUCCESS)
    {
        return TEE_SUCCESS;
    }
    if (rc == TEE_ERROR_ACCESS_DENIED)
    {
        rc = TEE_SeekObjectData(object, -sizeof(data), TEE_DATA_SEEK_CUR);
        if (rc)
            return rc;
        rc = TEE_ReadObjectData(object, &data, sizeof(data), &count);
        if (rc)
            return rc;
        if (count != sizeof(data))
            return TEE_ERROR_BAD_FORMAT;
        data.flag |= ACL_META_FLAG_VALID_MASK;
        rc = TEE_SeekObjectData(object, -sizeof(data), TEE_DATA_SEEK_CUR);
        if (rc)
            return rc;
        rc = TEE_WriteObjectData(object, &data, sizeof(data));
        return rc;
    }
    TEE_GetObjectInfo(object, &objectInfo);
    rc = TEE_TruncateObjectData(object, objectInfo.dataSize + sizeof(ACL_Meta));
    if (rc)
    {
        DMSG("[TEE_TruncateObjectData] falied with 0x%08x\n", rc);
        return rc;
    }
    rc = TEE_SeekObjectData(object, objectInfo.dataSize, TEE_DATA_SEEK_SET);
    if (rc)
        return rc;
    data.uuid = uuid;
    data.flag = ACL_META_FLAG_VALID_MASK;
    rc = TEE_WriteObjectData(object, &data, sizeof(data));
    return rc;
}

TEE_Result KA_CMD_Find(TEE_UUID host, TEE_UUID guest)
{
    TEE_ObjectHandle object;
    TEE_Result rc = TEE_SUCCESS;
    if (UUID_EQUAL(host, guest))
        return TEE_SUCCESS;
    rc = KA_ACL_Open(&object, host);
    if (rc)
        return rc;
    rc = KA_ACL_Find(object, guest);
    KA_ACL_Close(object);
    return rc;
}

TEE_Result KA_CMD_Add(TEE_UUID host, TEE_UUID guest)
{
    TEE_ObjectHandle object;
    TEE_Result rc = TEE_SUCCESS;
    if (UUID_EQUAL(host, guest))
        return TEE_ERROR_BAD_PARAMETERS;
    rc = KA_ACL_Open(&object, host);
    if (rc == TEE_ERROR_ITEM_NOT_FOUND)
    {
        rc = KA_ACL_Create(&object, host);
    }
    if (rc)
        return rc;
    rc = KA_ACL_Add(object, guest);
    KA_ACL_Close(object);
    if (rc)
    {
        EMSG("Error 0x%08x", rc);
    }
    return rc;
}

TEE_Result KA_CMD_Delete(TEE_UUID host, TEE_UUID guest)
{
    TEE_ObjectHandle object;
    TEE_Result rc = TEE_SUCCESS;
    if (UUID_EQUAL(host, guest))
        return TEE_ERROR_BAD_PARAMETERS;
    rc = KA_ACL_Open(&object, host);
    if (rc)
        return rc;
    rc = KA_ACL_Delete(object, guest);
    KA_ACL_Close(object);
    if (rc)
    {
        EMSG("Error 0x%08x", rc);
    }
    return rc;
}

TEE_Result KA_CMD_Remove(TEE_UUID uuid)
{
    DMSG("KA_CMD_Remove\n");
    char *obj_id = uuid2str(&uuid);
    size_t obj_id_size = strlen(obj_id);
    TEE_Result rc = TEE_SUCCESS;
    DMSG("key_id\n");
    char key_id[KEY_ID_MAX_SIZE];
    size_t key_id_size = snprintf(key_id, KEY_ID_MAX_SIZE, "%s.key", obj_id);
    TEE_ObjectHandle object;
    DMSG("Try to remove acl\n");
    rc = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, obj_id, obj_id_size, TEE_DATA_FLAG_ACCESS_WRITE_META, &object);
    if (rc)
        return rc;

    rc = TEE_CloseAndDeletePersistentObject1(object);
    if (rc)
        return rc;

    DMSG("Try to remove key pair\n");
    rc = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, key_id, key_id_size, TEE_DATA_FLAG_ACCESS_WRITE_META, &object);
    if (rc)
        return rc;

    rc = TEE_CloseAndDeletePersistentObject1(object);
    if (rc)
        return rc;

    return TEE_SUCCESS;
}

TEE_Result KA_CMD_GetPublicKey(TEE_UUID uuid, void *n, size_t *n_size, void *e, size_t *e_size)
{
    return KA_CMD_GetPrivateKey(uuid, n, n_size, e, e_size, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0);
}

TEE_Result KA_CMD_GetPrivateKey(TEE_UUID uuid, void *n, size_t *n_size, void *e, size_t *e_size, void *d, size_t *d_size, void *p, size_t *p_size, void *q, size_t *q_size, void *dmp1, size_t *dmp1_size, void *dmq1, size_t *dmq1_size, void *iqmp, size_t *iqmp_size)
{
    char key_id[KEY_ID_MAX_SIZE];
    size_t key_id_size = snprintf(key_id, KEY_ID_MAX_SIZE, "%s.key", uuid2str(&uuid));
    TEE_ObjectHandle object;
    TEE_Result rc = TEE_SUCCESS;
    DMSG("Get Key [%s]",key_id);
    rc = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, key_id, key_id_size, TEE_DATA_FLAG_SHARE_READ, &object);
    if (rc)
        return rc;

    if (n)
    {
        rc = TEE_GetObjectBufferAttribute(object, TEE_ATTR_RSA_MODULUS, n, n_size);
        if (rc)
            goto free_obj_out;
    }

    if (e)
    {
        rc = TEE_GetObjectBufferAttribute(object, TEE_ATTR_RSA_PUBLIC_EXPONENT, e, e_size);
        if (rc)
            goto free_obj_out;
    }

    if (d)
    {
        rc = TEE_GetObjectBufferAttribute(object, TEE_ATTR_RSA_PRIVATE_EXPONENT, d, d_size);
        if (rc)
            goto free_obj_out;
    }

    if (p)
    {
        rc = TEE_GetObjectBufferAttribute(object, TEE_ATTR_RSA_PRIME1, p, p_size);
        if (rc)
            goto free_obj_out;
    }

    if (q)
    {
        rc = TEE_GetObjectBufferAttribute(object, TEE_ATTR_RSA_PRIME2, q, q_size);
        if (rc)
            goto free_obj_out;
    }

    if (dmp1)
    {
        rc = TEE_GetObjectBufferAttribute(object, TEE_ATTR_RSA_EXPONENT1, dmp1, dmp1_size);
        if (rc)
            goto free_obj_out;
    }

    if (dmq1)
    {
        rc = TEE_GetObjectBufferAttribute(object, TEE_ATTR_RSA_EXPONENT2, dmq1, dmq1_size);
        if (rc)
            goto free_obj_out;
    }

    if (iqmp)
    {
        rc = TEE_GetObjectBufferAttribute(object, TEE_ATTR_RSA_COEFFICIENT, iqmp, dmq1_size);
        if (rc)
            goto free_obj_out;
    }
free_obj_out:
    TEE_CloseObject(object);
    return rc;
}

TEE_Result KA_CMD_GetPrivateKey0(TEE_UUID uuid, void *n, size_t *n_size, void *e, size_t *e_size, void *d, size_t *d_size, void *p, size_t *p_size)
{
    return KA_CMD_GetPrivateKey(uuid, n, n_size, e, e_size, d, d_size, p, p_size, NULL, 0, NULL, 0, NULL, 0, NULL, 0);
}

TEE_Result KA_CMD_GetPrivateKey1(TEE_UUID uuid, void *q, size_t *q_size, void *dmp1, size_t *dmp1_size, void *dmq1, size_t *dmq1_size, void *iqmp, size_t *iqmp_size)
{
    return KA_CMD_GetPrivateKey(uuid, NULL, 0, NULL, 0, NULL, 0, NULL, 0, q, q_size, dmp1, dmp1_size, dmq1, dmq1_size, iqmp, iqmp_size);
}

TEE_Result parse_guest_uuid(TEE_Param param, TEE_UUID *guest)
{
    TEE_Result rc = TEE_SUCCESS;
    char *guest_path = NULL;
    TEE_Identity identity;

    guest_path = TEE_Malloc(4096, 0);
    if (guest_path == NULL)
    {
        return TEE_ERROR_OUT_OF_MEMORY;
    }

    if (param.memref.size > 4096 - 1)
    {
        rc = TEE_ERROR_BAD_PARAMETERS;
        goto out_free;
    }
    TEE_MemMove(guest_path, param.memref.buffer, param.memref.size);
    guest_path[param.memref.size] = 0;
    DMSG("Guest path [%s]\n", guest_path);

    rc = path2uuid(guest_path, guest);
    if (rc)
        goto out_free;
    DMSG("Guest UUID [%s]\n", uuid2str(guest));
out_free:

    TEE_Free(guest_path);
    return rc;
}

/**
 * @brief add guest uuid to host access control list
 * @param param_types TEE_PARAM_TYPE_MEMREF_INPUT TEE_PARAM_TYPE_NONE TEE_PARAM_TYPE_NONE TEE_PARAM_TYPE_NONE
 * @param params[0] guest_path : guest bin absolute path, such as /usr/bin/guest
 */
TEE_Result KA_ADD(uint32_t param_types, TEE_Param params[4])
{
    TEE_UUID guest;
    TEE_Identity identity;
    TEE_Result rc = TEE_SUCCESS;
    if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
                                       TEE_PARAM_TYPE_NONE,
                                       TEE_PARAM_TYPE_NONE,
                                       TEE_PARAM_TYPE_NONE))
        return TEE_ERROR_BAD_PARAMETERS;

    rc = parse_guest_uuid(params[0], &guest);
    if (rc)
        return rc;

    rc = TEE_GetPropertyAsIdentity(TEE_PROPSET_CURRENT_CLIENT, "gpd.client.identity", &identity);
    if (rc)
        return rc;

    DMSG("Host : %s\n", uuid2str(&(identity.uuid)));

    return KA_CMD_Add(identity.uuid, guest);
}

/**
 * @brief delete guest uuid to host access control list
 * @param param_types TEE_PARAM_TYPE_MEMREF_INPUT TEE_PARAM_TYPE_NONE TEE_PARAM_TYPE_NONE TEE_PARAM_TYPE_NONE
 * @param params[0] guest_path : guest bin absolute path, such as /usr/bin/guest
 */
TEE_Result KA_DELETE(uint32_t param_types, TEE_Param params[4])
{
    TEE_UUID guest;
    TEE_Identity identity;
    TEE_Result rc = TEE_SUCCESS;
    if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
                                       TEE_PARAM_TYPE_NONE,
                                       TEE_PARAM_TYPE_NONE,
                                       TEE_PARAM_TYPE_NONE))
        return TEE_ERROR_BAD_PARAMETERS;

    rc = parse_guest_uuid(params[0], &guest);
    if (rc)
        return rc;

    rc = TEE_GetPropertyAsIdentity(TEE_PROPSET_CURRENT_CLIENT, "gpd.client.identity", &identity);
    if (rc)
        return rc;

    DMSG("Host : %s\n", uuid2str(&(identity.uuid)));

    return KA_CMD_Delete(identity.uuid, guest);
}

/**
 * @brief remove guest contorl data file, must be called by admin_path bin file
 * @param param_types TEE_PARAM_TYPE_MEMREF_INPUT TEE_PARAM_TYPE_NONE TEE_PARAM_TYPE_NONE TEE_PARAM_TYPE_NONE
 * @param params[0] guest_path : guest bin absolute path, such as /usr/bin/guest
 */
TEE_Result KA_REMOVE(uint32_t param_types, TEE_Param params[4])
{

    TEE_UUID guest, admin;
    TEE_Identity identity;
    TEE_Result rc = TEE_SUCCESS;
    if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
                                       TEE_PARAM_TYPE_NONE,
                                       TEE_PARAM_TYPE_NONE,
                                       TEE_PARAM_TYPE_NONE))
        return TEE_ERROR_BAD_PARAMETERS;

    rc = path2uuid(admin_path, &admin);
    if (rc)
        return rc;
    rc = TEE_GetPropertyAsIdentity(TEE_PROPSET_CURRENT_CLIENT, "gpd.client.identity", &identity);
    if (rc)
        return rc;
    if (!UUID_EQUAL(identity.uuid, admin))
        return TEE_ERROR_ACCESS_DENIED;
    rc = parse_guest_uuid(params[0], &guest);
    if (rc)
        return rc;
    DMSG("Host : %s\n", uuid2str(&(identity.uuid)));

    return KA_CMD_Remove(guest);
}

/**
 * @brief get guest rsa public key
 * @param param_types TEE_PARAM_TYPE_MEMREF_INPUT TEE_PARAM_TYPE_MEMREF_OUTPUT TEE_PARAM_TYPE_MEMREF_OUTPUT TEE_PARAM_TYPE_NONE
 * @param params[0] guest_path : guest bin absolute path, such as /usr/bin/guest
 * @param params[1] n : rsa key part n
 * @param params[2] e : rsa key part e
 */
TEE_Result KA_RSA_PUB(uint32_t param_types, TEE_Param params[4])
{
    TEE_UUID guest;
    TEE_Identity identity;
    TEE_Result rc = TEE_SUCCESS;

    if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
                                       TEE_PARAM_TYPE_MEMREF_OUTPUT,
                                       TEE_PARAM_TYPE_MEMREF_OUTPUT,
                                       TEE_PARAM_TYPE_NONE))
        return TEE_ERROR_BAD_PARAMETERS;

    rc = parse_guest_uuid(params[0], &guest);
    if (rc)
        return rc;

    rc = TEE_GetPropertyAsIdentity(TEE_PROPSET_CURRENT_CLIENT, "gpd.client.identity", &identity);
    if (rc)
        return rc;

    DMSG("Host : %s\n", uuid2str(&(identity.uuid)));
    DMSG("Guest: %s\n", uuid2str(&(guest)));

    rc = KA_CMD_Find(guest, identity.uuid);
    if (rc)
        return rc;

    return KA_CMD_GetPublicKey(guest, params[1].memref.buffer, &params[1].memref.size, params[2].memref.buffer, &params[2].memref.size);
}

/**
 * @brief get host rsa private key part 0 [n,e,d,p]
 * @param param_types TEE_PARAM_TYPE_MEMREF_OUTPUT TEE_PARAM_TYPE_MEMREF_OUTPUT TEE_PARAM_TYPE_MEMREF_OUTPUT TEE_PARAM_TYPE_MEMREF_OUTPUT
 * @param params[0] n : rsa key part n
 * @param params[1] e : rsa key part e
 * @param params[2] d : rsa key part d
 * @param params[3] p : rsa key part p
 */
TEE_Result KA_RSA_PRI_0(uint32_t param_types, TEE_Param params[4])
{
    TEE_Identity identity;
    TEE_Result rc = TEE_SUCCESS;

    if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_OUTPUT,
                                       TEE_PARAM_TYPE_MEMREF_OUTPUT,
                                       TEE_PARAM_TYPE_MEMREF_OUTPUT,
                                       TEE_PARAM_TYPE_MEMREF_OUTPUT))
        return TEE_ERROR_BAD_PARAMETERS;

    rc = TEE_GetPropertyAsIdentity(TEE_PROPSET_CURRENT_CLIENT, "gpd.client.identity", &identity);
    if (rc)
        return rc;

    DMSG("Host : %s\n", uuid2str(&(identity.uuid)));

    return KA_CMD_GetPrivateKey0(identity.uuid, params[0].memref.buffer, &params[0].memref.size, params[1].memref.buffer, &params[1].memref.size,
                                 params[2].memref.buffer, &params[2].memref.size, params[3].memref.buffer, &params[3].memref.size);
}

/**
 * @brief get host rsa private key part 1 [q,dmp1,dmq1,iqmp1]
 * @param param_types TEE_PARAM_TYPE_MEMREF_OUTPUT TEE_PARAM_TYPE_MEMREF_OUTPUT TEE_PARAM_TYPE_MEMREF_OUTPUT TEE_PARAM_TYPE_MEMREF_OUTPUT
 * @param params[0] q       : rsa key part q
 * @param params[1] dmp1    : rsa key part dmp1
 * @param params[2] dmq1    : rsa key part dmq1
 * @param params[3] iqmp1   : rsa key part iqmp1
 */
TEE_Result KA_RSA_PRI_1(uint32_t param_types, TEE_Param params[4])
{
    TEE_Identity identity;
    TEE_Result rc = TEE_SUCCESS;

    if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_OUTPUT,
                                       TEE_PARAM_TYPE_MEMREF_OUTPUT,
                                       TEE_PARAM_TYPE_MEMREF_OUTPUT,
                                       TEE_PARAM_TYPE_MEMREF_OUTPUT))
        return TEE_ERROR_BAD_PARAMETERS;

    rc = TEE_GetPropertyAsIdentity(TEE_PROPSET_CURRENT_CLIENT, "gpd.client.identity", &identity);
    if (rc)
        return rc;

    DMSG("Host : %s\n", uuid2str(&(identity.uuid)));

    return KA_CMD_GetPrivateKey1(identity.uuid, params[0].memref.buffer, &params[0].memref.size, params[1].memref.buffer, &params[1].memref.size,
                                 params[2].memref.buffer, &params[2].memref.size, params[3].memref.buffer, &params[3].memref.size);
}

TEE_Result KA_TEST(uint32_t param_types, TEE_Param params[4])
{
    (void)&params;

    if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE,
                                       TEE_PARAM_TYPE_NONE,
                                       TEE_PARAM_TYPE_NONE,
                                       TEE_PARAM_TYPE_NONE))
        return TEE_ERROR_BAD_PARAMETERS;

    extern void KA_CMD_Test();
    KA_CMD_Test();
}